package cn.redragon.soa.data.dao.impl;

import static org.apache.commons.collections4.IterableUtils.isEmpty;

import cn.redragon.soa.common.util.SecurityUtil;
import cn.redragon.soa.data.entity.BaseEntity;
import com.google.common.collect.Lists;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

public class BaseDaoImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {

    private final JpaEntityInformation<T, ?> jpaEntityInformation;

    public BaseDaoImpl(JpaEntityInformation<T, ?> entityInformation,
                       EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.jpaEntityInformation = entityInformation;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public <S extends T> S save(S entity) {
        if (BaseEntity.class.isAssignableFrom(entity.getClass())) {
            LocalDateTime now = LocalDateTime.now();
            BaseEntity base = (BaseEntity) entity;
            if (jpaEntityInformation.isNew(entity)) {
                base.setCreateTime(Optional.ofNullable(base.getCreateTime()).orElse(now));
                base.setCreator(Optional.ofNullable(base.getCreator()).orElse(SecurityUtil.getProfile()));
            }
            base.setUpdater(Optional.ofNullable(base.getUpdater()).orElse(SecurityUtil.getProfile()));
            base.setUpdateTime(now);
        }

        return super.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public <S extends T> List<S> saveAll(Iterable<S> entities) {
        List<S> result = Lists.newArrayList();
        if (isEmpty(entities)) {
            return result;
        }
        Iterator<S> it = entities.iterator();
        while (it.hasNext()) {
            result.add(this.save(it.next()));
        }
        return result;
    }

}
